{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"https://csdms.colorado.edu/wiki/ESPIn2020\"><img style=\"float: center; width: 75%\" src=\"../../media/ESPIn.png\"></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Programming with Python\n",
    "## Analyzing Topographic Data\n",
    "### minutes: 30\n",
    "\n",
    ">## Learning Objectives\n",
    ">*   Explain what a library is, and what libraries are used for\n",
    ">*   Load a Python library and use the tools it contains\n",
    ">*   Read data from a file into a program\n",
    ">*   Assign values to variables\n",
    ">*   Select individual values and subsections from data\n",
    ">*   Perform operations on arrays of data\n",
    ">*   Display simple graphs\n",
    "\n",
    "While a lot of powerful tools are built into languages like Python,\n",
    "even more tools exist in [libraries](reference.html#library).\n",
    "\n",
    "In order to load the elevation data,\n",
    "we need to [import](reference.html#import) a library called NumPy.\n",
    "You should use this library if you want to do fancy things with numbers (ie. math),\n",
    "especially if you have matrices or arrays.\n",
    "We can load NumPy using:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Importing a library is like pulling a toolbox out of a\n",
    "storage locker and placing it on your workbench, making everything inside the toolbox accessible. Python has a set of built-in functions that are always available (the tools you always have available) and libraries provide\n",
    "additional functionality (the specialized tools in the toolbox you only sometimes need).\n",
    "\n",
    "\n",
    "Once we’ve loaded the library, we can\n",
    "call a function inside that library to read the data file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[3198.8391, 3198.123 , 3197.1584, ..., 2583.3293, 2585.4368,\n",
       "        2589.1079],\n",
       "       [3198.3306, 3197.5242, 3196.4102, ..., 2582.6992, 2584.9167,\n",
       "        2587.801 ],\n",
       "       [3197.9968, 3196.9197, 3195.7188, ..., 2581.8328, 2583.8159,\n",
       "        2586.0325],\n",
       "       ...,\n",
       "       [3325.1509, 3334.7822, 3343.3154, ..., 2780.8191, 2769.3235,\n",
       "        2762.373 ],\n",
       "       [3325.0823, 3335.0308, 3345.4963, ..., 2775.3345, 2765.7131,\n",
       "        2759.6555],\n",
       "       [3326.6824, 3336.5305, 3348.1343, ..., 2769.7661, 2762.5242,\n",
       "        2756.6877]])"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numpy.loadtxt('../../data/topo.asc', delimiter=',')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The expression `numpy.loadtxt(...)` is a [function call](reference.html#function-call)\n",
    "that asks Python to run the function `loadtxt` that belongs to the `numpy` library.\n",
    "This [dotted notation](reference.html#dotted-notation), with the syntax `thing.component`, is used\n",
    "everywhere in Python to refer to parts of things.\n",
    "\n",
    "The function call to `numpy.loadtxt` has two [parameters](reference.html#parameter):\n",
    "the name of the file we want to read,\n",
    "and the [delimiter](reference.html#delimiter) that separates values on a line.\n",
    "Both need to be character strings (or [strings](reference.html#string), for short)\n",
    "so we write them in quotes.\n",
    "\n",
    "Within the Jupyter (iPython) notebook, pressing Shift+Enter runs the\n",
    "commands in the selected cell. Because we haven't told iPython what to\n",
    "do with the output of `numpy.loadtxt`, the notebook just displays it on\n",
    "the screen. In this case, that output is the data we just loaded. By\n",
    "default, only a few rows and columns are shown (with `...` to omit\n",
    "elements when displaying big arrays).\n",
    "\n",
    "Our call to `numpy.loadtxt` read the file but didn’t save it to memory.\n",
    "In order to access the data, we need to [assign](reference.html#assignment) the values to a [variable](reference.html#variable).\n",
    "A variable is just a name that refers to an object. Python’s variables\n",
    "must begin with a letter and are [case sensitive](reference.html#case-sensitive). We can assign a\n",
    "variable name to an object using `=`.\n",
    "\n",
    "\n",
    "## Objects and their names\n",
    "\n",
    "What happens when a function is called but the output is not assigned to\n",
    "a variable is a bit more complicated than simply not saving it. The call\n",
    "to `numpy.loadtxt` read the file and created an object in memory that\n",
    "contains the data, but because we didn't assign it to a variable name,\n",
    "there is no way for us to call this object. While this difference might\n",
    "seem irrelevant (and, in practice, it probably is), it will be important to\n",
    "consider how variable names are assigned to objects when we talk about\n",
    "mutable and immutable objects later on.\n",
    "\n",
    "A good explanation of how Python handles variables and objects can be\n",
    " found [in Jeff Knupp's blog](https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/).\n",
    "\n",
    "Let’s re-run numpy.loadtxt and assign the output to a variable name:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [],
   "source": [
    "topo = numpy.loadtxt('../../data/topo.asc', delimiter=',')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This command doesn’t produce any visible output. If we want to see the\n",
    "data, we can print the variable’s value with the command `print`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[3198.8391 3198.123  3197.1584 ... 2583.3293 2585.4368 2589.1079]\n",
      " [3198.3306 3197.5242 3196.4102 ... 2582.6992 2584.9167 2587.801 ]\n",
      " [3197.9968 3196.9197 3195.7188 ... 2581.8328 2583.8159 2586.0325]\n",
      " ...\n",
      " [3325.1509 3334.7822 3343.3154 ... 2780.8191 2769.3235 2762.373 ]\n",
      " [3325.0823 3335.0308 3345.4963 ... 2775.3345 2765.7131 2759.6555]\n",
      " [3326.6824 3336.5305 3348.1343 ... 2769.7661 2762.5242 2756.6877]]\n"
     ]
    }
   ],
   "source": [
    "print(topo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Check your understanding\n",
    "\n",
    " Track how variable names and values are connected after each statement in the following program:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "95.0\n"
     ]
    }
   ],
   "source": [
    " mass = 47.5\n",
    " age = 122\n",
    " mass = mass * 2.0\n",
    " age = age - 20\n",
    "\n",
    "print(mass)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Sorting out references\n",
    "\n",
    " What does the following program print out?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hopper Grace\n"
     ]
    }
   ],
   "source": [
    " first, second = 'Grace', 'Hopper'\n",
    " third, fourth = second, first\n",
    " print(third, fourth)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using its variable name, we can see that [type](reference.html#type) of object the variable name `topo` is assigned \n",
    "to:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'numpy.ndarray'>\n"
     ]
    }
   ],
   "source": [
    "print(type(topo))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The function `type` tells us that the variable name `topo` currently\n",
    "points to an N-dimensional array created by the NumPy library. We can also get the shape of the\n",
    "array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(500, 500)\n"
     ]
    }
   ],
   "source": [
    "print(topo.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This tells us that `topo` has 500 rows and 500 columns. The file\n",
    "we imported contains elevation data (in meters, 2 degree spacing) for an\n",
    "area along the Front Range of Colorado, so the area that this array represents is 1 km x 1 km.\n",
    "\n",
    "The object of\n",
    "type `numpy.ndarray` that the variable `topo` is assigned to contains the values of the array\n",
    "as well as some extra information about the array. These are the [members](reference.html#member) or attributes of the object, and they\n",
    "describe the data in the same way an adjective describes a noun. The\n",
    "command `topo.shape` calls the `shape` attribute of the object with the variable name\n",
    "`topo` that describes its dimensions. We use the same dotted notation\n",
    "for the attributes of objects that we use for the functions inside\n",
    "libraries because they have the same part-and-whole relationship.\n",
    "\n",
    "\n",
    "## len() and other built-in functions\n",
    "\n",
    "The function `len()` returns the length of the longest axis of a\n",
    "sequence (a numpy array, a list, etc.). Because it is a built-in\n",
    "function, it is always available for the Python interpreter and doesn't\n",
    "have to be imported. The function `type()` is another built in function.\n",
    "You can read about them in the [Python docs](https://docs.python.org/2/library/functions.html).\n",
    "\n",
    "Ex. What is the length of the variable `topo`? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "500"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(topo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, that is weird, topo is supposed to be a 500$\\times$500 matrix. In numpy, the array is actually stored as an array of arrays. \n",
    "\n",
    "Find a way to return the number of columns and rows using the built-in len() function "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "500\n",
      "500\n"
     ]
    }
   ],
   "source": [
    "print(len(topo) )   # cols\n",
    "print(len(topo[0])) # rows"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Who's who in the memory\n",
    "\n",
    " You can use the whos command at any time to see what variables you have\n",
    " created and what modules you have loaded into the computers memory. As\n",
    " this is an IPython command, it will only work if you are in an iPython\n",
    " terminal or the Jupyter Notebook.\n",
    " \n",
    " Try it, check what is currently on your memory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Variable   Type       Data/Info\n",
      "-------------------------------\n",
      "age        int        102\n",
      "first      str        Grace\n",
      "fourth     str        Grace\n",
      "mass       float      95.0\n",
      "np         module     <module 'numpy' from '/Us<...>kages/numpy/__init__.py'>\n",
      "numpy      module     <module 'numpy' from '/Us<...>kages/numpy/__init__.py'>\n",
      "second     str        Hopper\n",
      "third      str        Hopper\n",
      "topo       ndarray    500x500: 250000 elems, type `float64`, 2000000 bytes (1.9073486328125 Mb)\n",
      "topo_new   ndarray    4x6: 24 elems, type `float64`, 192 bytes\n"
     ]
    }
   ],
   "source": [
    "whos"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotting\n",
    " \n",
    "Rasters are just big two dimensional arrays of values. In the case of DEMs, those values\n",
    "are elevations. It's very hard to get a good sense of what this landscape\n",
    "looks like by looking directly at the data. This information is better\n",
    "conveyed through plots and graphics.\n",
    "\n",
    "Data visualization deserves an entire lecture (or course) of its own,\n",
    "but we can explore a few features of Python's `matplotlib` library here.\n",
    "While there is no \"official\" plotting library in Python, this package is\n",
    "the de facto standard.\n",
    "\n",
    "We start by importing the `pyplot` module from the library `matplotlib`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "ename": "ImportError",
     "evalue": "dlopen(/Users/beca4397/opt/anaconda3/lib/python3.7/site-packages/PIL/_imaging.cpython-37m-darwin.so, 2): Library not loaded: @rpath/libwebp.7.dylib\n  Referenced from: /Users/beca4397/opt/anaconda3/lib/libtiff.5.dylib\n  Reason: Incompatible library version: libtiff.5.dylib requires version 9.0.0 or later, but libwebp.7.dylib provides version 8.0.0",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-35-864e826dab68>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpyplot\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/pyplot.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m   2280\u001b[0m     \u001b[0mdict\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__setitem__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"backend\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrcsetup\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_auto_backend_sentinel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2281\u001b[0m \u001b[0;31m# Set up the backend.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2282\u001b[0;31m \u001b[0mswitch_backend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"backend\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2283\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2284\u001b[0m \u001b[0;31m# Just to be safe.  Interactive mode can be turned on without\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/pyplot.py\u001b[0m in \u001b[0;36mswitch_backend\u001b[0;34m(newbackend)\u001b[0m\n\u001b[1;32m    219\u001b[0m         else \"matplotlib.backends.backend_{}\".format(newbackend.lower()))\n\u001b[1;32m    220\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 221\u001b[0;31m     \u001b[0mbackend_mod\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mimport_module\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackend_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    222\u001b[0m     Backend = type(\n\u001b[1;32m    223\u001b[0m         \"Backend\", (matplotlib.backends._Backend,), vars(backend_mod))\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/importlib/__init__.py\u001b[0m in \u001b[0;36mimport_module\u001b[0;34m(name, package)\u001b[0m\n\u001b[1;32m    125\u001b[0m                 \u001b[0;32mbreak\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    126\u001b[0m             \u001b[0mlevel\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 127\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0m_bootstrap\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_gcd_import\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mlevel\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    129\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/ipykernel/pylab/backend_inline.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m from matplotlib.backends.backend_agg import (\n\u001b[0m\u001b[1;32m     10\u001b[0m     \u001b[0mnew_figure_manager\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mFigureCanvasAgg\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     49\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_has_pil\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m     \u001b[0;32mfrom\u001b[0m \u001b[0mPIL\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mImage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     52\u001b[0m \u001b[0mbackend_version\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'v2.2'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/PIL/Image.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     67\u001b[0m     \u001b[0;31m# Also note that Image.core is not a publicly documented interface,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     68\u001b[0m     \u001b[0;31m# and should be considered private and subject to change.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 69\u001b[0;31m     \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0m_imaging\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcore\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     70\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     71\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0m__version__\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"PILLOW_VERSION\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mImportError\u001b[0m: dlopen(/Users/beca4397/opt/anaconda3/lib/python3.7/site-packages/PIL/_imaging.cpython-37m-darwin.so, 2): Library not loaded: @rpath/libwebp.7.dylib\n  Referenced from: /Users/beca4397/opt/anaconda3/lib/libtiff.5.dylib\n  Reason: Incompatible library version: libtiff.5.dylib requires version 9.0.0 or later, but libwebp.7.dylib provides version 8.0.0"
     ]
    }
   ],
   "source": [
    "import matplotlib.pyplot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> ## Some IPython magic\n",
    "> \n",
    "> If you're using an IPython / Jupyter notebook, you'll need to execute\n",
    "> the following command in order for the plots to appear in\n",
    "> the notebook instead of a separate window:\n",
    "> "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> The `%` indicates an IPython magic function - a function that is only\n",
    "> valid within the notebook environment. Note that you only have to\n",
    "> execute this function once per notebook.\n",
    "\n",
    "We can use the function `imshow` within `matplotlib.pyplot` to display arrays as a 2D\n",
    "image. \n",
    "\n",
    "Try to display the 2D `topo` array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "matplotlib.pyplot.imshow(topo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Indexing\n",
    "\n",
    "We can access individual values in an array using an [index](reference.html#index) in square brackets:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('elevation at the corner of topo:', topo[0,0], 'meters')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print( 'elevation at some random point in topo:', topo[137,65],\n",
    "'meters')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When referring to entries in a two dimensional array, the indices are\n",
    "ordered `[row,column]`. The expression `topo[137, 65]` should not surprise\n",
    "you but `topo[0,0]` might. Programming languages like Fortran and MATLAB\n",
    "start counting at 1 because that’s what (most) humans have done for\n",
    "thousands of years. Languages in the C family (including C++, Java,\n",
    "Perl, and Python) count from 0 because that’s simpler for computers to\n",
    "do. So if we have an M×N array in Python, the indices go from 0 to M-1\n",
    "on the first axis (rows) and 0 to N-1 on the second (columns). In\n",
    "MATLAB, the same array (or matrix) would have indices that go from 1 to\n",
    "M and 1 to N. Zero-based indexing takes a bit of getting used to, but\n",
    "one way to remember the rule is that the index is how many steps we have\n",
    "to take from the start to get to the item we want.\n",
    "\n",
    "Python also allows for negative indices to refer to the position of\n",
    "elements with respect to the end of each axis. An index of -1 refer to\n",
    "the last item in a list, -2 is the second to last, and so on. Since\n",
    "index `[0,0]` is the upper left corner of an array, index `[-1,-1]`\n",
    "therefore the lower right corner of the array. \n",
    "\n",
    "Print the lower right corner of the `topo` array: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo[-1,-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "attributes": {
     "classes": [
      "output"
     ],
     "id": ""
    }
   },
   "source": [
    "Print the upper left corner of the `topo` array: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "attributes": {
     "classes": [
      "output"
     ],
     "id": ""
    }
   },
   "outputs": [],
   "source": [
    "print(topo[0,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> ## In the Corner\n",
    ">\n",
    "> What may also surprise you is that when Python displays an array,\n",
    "> it shows the element with index `[0, 0]` in the upper left corner\n",
    "> rather than the lower left.\n",
    "> This is consistent with the way mathematicians draw matrices,\n",
    "> but different from the Cartesian coordinates.\n",
    "> The indices are (row, column) instead of (column, row) for the same reason,\n",
    "> which can be confusing when plotting data.\n",
    "\n",
    "## Slicing\n",
    "\n",
    "A command like `topo[0,0]` selects a single element in the array `topo`.\n",
    "Indices can also be used to [slice](reference.html#slice) sections of the array. For example, we\n",
    "can select the top left quarter of the array like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo[0:5, 0:5])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The slice `[0:5]` means \"Start at index 0 and go along the axis up to,\n",
    "but not including, index 5\".\n",
    "\n",
    "We don’t need to include the upper or lower bound of the slice if we\n",
    "want to go all the way to the edge. If we don’t include the lower bound,\n",
    "Python uses 0 by default; if we don’t include the upper bound, the slice\n",
    "runs to the end of the axis. If we don’t include either (i.e., if we\n",
    "just use ‘:’), the slice includes everything. \n",
    "\n",
    "Print out the first 5 rows and last 6 columns op the topo array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo[:4, -6:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Point elevations: Practice your skills \n",
    " \n",
    " Use indexing to answer the following questions and check your answers\n",
    " against the data visualization:\n",
    " \n",
    " * Is the NW corner of the region higher than the SW corner? What's the elevation difference? You can assume the NW corner to be in the upper left corner of the matrix (NW of at [0,0], not the Cartesian NW, see also (In the Corner)\n",
    " * What's the elevation difference between the NE corner and the SE corner?\n",
    " * What's the elevation at the center of the region shown in the array?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Slicing strings\n",
    " \n",
    " Indexing and slicing behave the same way for any type of sequence,\n",
    " including numpy arrays, lists, and strings. Create a new variable called\n",
    " `text` and assign it the string \"The quick brown fox jumped over the\n",
    " lazy dog.\" (note the capitalization and punctuation in each sentence, and include the quotes so Python recognizes it as a string).\n",
    " Then use slicing and the `print()` statement to create these frases:\n",
    " \n",
    " * the lazy dog.\n",
    " * The fox jumped over the dog\n",
    " * The lazy fox jumped over the quick brown dog.\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "text=\"The quick brown fox jumped over the lazy dog.\"\n",
    "\n",
    "print(text[0:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Plotting smaller regions \n",
    " \n",
    " Use the function `imshow` from `matplotlib.pyplot` to make one plot\n",
    " showing the northern half of the region and another plot showing the southern\n",
    " half.\n",
    " \n",
    " Then try making four separate plots showing each quarter of the region\n",
    " separately."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Non-square arrays\n",
    "  \n",
    " We've been using `len(topo)/2` as both the row and column indices of the\n",
    " center point in the array `topo`. This doesn't work with an array that's\n",
    " not square (has different height and width).\n",
    " \n",
    " * Take a (small) slice of the array `topo` and assign it to a new\n",
    " variable. Make this new array have a height longer than its width, and\n",
    " make both the height and width even numbers (4 x 6 is a good size)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "topo_new =topo[:4,-6:]\n",
    "print(topo_new)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "  * Access the center point of your new array. Write the indices using variables, not numbers (ie. don't write `t[2,3]`) (Hint: `topo.shape` gives the number of rows and columns in `topo`. The function `len(topo)` returns the length of the first axis. Instead of using `len()`, assign the output of `shape` to a variable and use indexing). Are you *really* pointing to the center of your array? How far off are you? "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo_new[int(topo_new.shape[0]/2),int(topo_new.shape[1]/2)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Calculating indices\n",
    "What happens if you try to access the value of topo at calcualted indices such as : `len(topo)/2` ? \n",
    "How can you resolve? \n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "topo[int(topo.shape[0]/2),int(topo.shape[1]/2)]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is all about casting variables (that is transforming them from one data type into another one). \n",
    "If you want to learn more about data types and casting, check out [this](https://github.com/donnemartin/data-science-ipython-notebooks/blob/master/numpy/02.01-Understanding-Data-Types.ipynb) repository of  Donne Martin. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Numerical operations on arrays\n",
    "\n",
    "We can perform basic mathematical operations on each individual element of a NumPy array. We can create a new array with elevations in feet:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "topo_in_feet = topo * 3.2808\n",
    "print('Elevation in meters:', topo[0,0])\n",
    "print('Elevation in feet:', topo_in_feet[0,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Arrays of the same size can be used together in arithmatic operations:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "double_topo = topo + topo\n",
    "print('Double topo:', double_topo[0,0], 'meters')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also perform statistical operations on arrays:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Mean elevation:', topo.mean(), 'meters')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> ## Methods vs. attributes\n",
    "> \n",
    "> `mean` is a method that belongs to the array `topo`, i.e., it is a\n",
    "> function `topo` can inherently call just because of its type.\n",
    "> When we call `topo.mean()`, we are asking `topo` to calculate its mean\n",
    "> value. Because it is a function, we need to include parenthesis in the\n",
    "> command. Because it is an `np.array`, `topo` also has an attribute called `shape`, but it doesn't include parenthesis because\n",
    "> attributes are objects, not functions.\n",
    "> \n",
    "> Python will kindly tell us if we mix up the parentheses:\n",
    "> "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "topo.mean"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NumPy arrays have many other useful methods:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('Highest elevation:', topo.max(), 'meters')\n",
    "print('Lowest elevation:', topo.min(), 'meters') "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also call methods on slices of the array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "half_len = int(len(topo) / 2)\n",
    "\n",
    "print('Highest elevation of NW quarter:', topo[:half_len,\n",
    ":half_len].max(), 'meters')\n",
    "\n",
    "print('Highest elevation of SE quarter:', topo[half_len:,\n",
    "half_len:].max(), 'meters' )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Methods can also be used along individual axes (rows or columns) of an\n",
    "array. If we want to see how the mean elevation changes with longitude\n",
    "(E-W), we can use the method along `axis=0`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo.mean(axis=0) )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To see how the mean elevation changes with latitude (N-S), we can use\n",
    "`axis=1`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(topo.mean(axis=1) )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Plotting, take two\n",
    " \n",
    "It's hard to get a sense of how the topography changes across the\n",
    "landscape from these big tables of numbers. A simpler way to display\n",
    "this information is with line plots.\n",
    "\n",
    "We are again going to use the `matplotlib` package for data\n",
    "visualization. Since we imported the `matplotlib.pyplot` library once\n",
    "already, those tools are available and can be called within Python. As a\n",
    "review, though, we are going to write every step needed to load and plot\n",
    "the data.\n",
    "\n",
    "We use the function `plot` to create two basic line plots of the\n",
    "topography:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "topo = np.loadtxt('../../data/topo.asc', delimiter=',')\n",
    "\n",
    "plt.plot(topo[0,:])\n",
    "plt.title('Topographic profile, northern edge')\n",
    "plt.ylabel('Elevation (m)')\n",
    "plt.xlabel('<-- West    East -->')\n",
    "plt.show()\n",
    "\n",
    "plt.plot(topo[-1,:], 'r--')\n",
    "plt.title('Topographic profile, southern edge')\n",
    "plt.ylabel('Elevation (m)')\n",
    "plt.xlabel('<-- West    East -->')\n",
    "plt.show() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](fig/output_74_0.png)\n",
    "![](fig/output_74_1.png)\n",
    "\n",
    "\n",
    "> ## Scientists dislike typing\n",
    ">\n",
    "> We will always use the syntax `import numpy` to import NumPy. However,\n",
    "> in order to save typing, it is [often\n",
    "> suggested](http://www.scipy.org/getting-started.html#an-example-script\n",
    "> ) to make a shortcut like so: `import numpy as np`. If you ever see\n",
    "> Python code using a NumPy function with `np` (for example,\n",
    "> `np.loadtxt(...)`), it's because they've used this shortcut.\n",
    "\n",
    "To better compare these profiles, we can plot them as separate lines in\n",
    "a single figure. Note that this is the default configuration in python 3. Unless a new figure instance is opened or the existing figure is shown (`plt.show`), all subsequent calls to `plt.plot` will use the same axes (until it reaches `plt.show()`). The argument `label=` holds the label that will appear in the legend."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np \n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "topo = np.loadtxt('../../data/topo.asc', delimiter=',')\n",
    "\n",
    "plt.plot(topo[0,:], label='North')\n",
    "\n",
    "plt.plot(topo[-1,:], 'r--', label='South')\n",
    "\n",
    "plt.plot(topo[int(len(topo)/2),:], 'g:', linewidth=3, label='Mid')\n",
    "\n",
    "plt.title('Topographic profiles')\n",
    "plt.ylabel('Elevation (m)')\n",
    "plt.xlabel('<-- West    East -->')\n",
    "plt.legend(loc = 'lower left')\n",
    "\n",
    "plt.show() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Practice your skills: Make your own plots \n",
    "\n",
    " Create three separate plots showing how the maximum (`numpy.max()`),\n",
    " minimum (`numpy.min()`), and mean (`numpy.mean()`) elevation changes\n",
    " with longitude. Label the axes and include a title for each of the\n",
    " plots (Hint: use `axis=0`).\n",
    "\n",
    " Convert the separate plots into a single plot that includes all three\n",
    " statistics (using `hold=True`). Create a legend."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ## Practice your skills: Subplots \n",
    "\n",
    " We often want to arrange separate plots in layouts with multiple rows\n",
    " and columns. The script below uses subplots to show the elevation\n",
    " profile at the western edge, the mid longitude, and eastern edge of\n",
    " the region. Subplots can be a little weird because they require the\n",
    " axes to be defined before plotting. Type (don't copy-past!) the code\n",
    " below to get a sense of how it works.\n",
    " \n",
    "This script uses a number of new commands. The function `plt.figure()`\n",
    "creates a space into which we will place the three plots. The parameter\n",
    "`figsize` tells Python how big to make this space. Each subplot is\n",
    "placed into the figure using the `subplot` command. The `subplot`\n",
    "command takes 3 parameters: the first denotes the total number of rows\n",
    "of subplots in the figure, the second is the total number of columns of\n",
    "subplots in the figure, and the final parameters identifies the\n",
    "position of the subplot in the grid. The axes of each subplot are\n",
    "called with different variable (axes1, axes2, axes3, axes4). Once a\n",
    "subplot is created, the axes can be labeled using the `set_xlabel()`\n",
    "(or `set_ylabel()`) method. `plt.show()` is called after the entire\n",
    "figure is set up."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "ename": "ImportError",
     "evalue": "dlopen(/Users/beca4397/opt/anaconda3/lib/python3.7/site-packages/PIL/_imaging.cpython-37m-darwin.so, 2): Library not loaded: @rpath/libwebp.7.dylib\n  Referenced from: /Users/beca4397/opt/anaconda3/lib/libtiff.5.dylib\n  Reason: Incompatible library version: libtiff.5.dylib requires version 9.0.0 or later, but libwebp.7.dylib provides version 8.0.0",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mImportError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-34-3c6b8fbbb009>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpyplot\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      3\u001b[0m \u001b[0mget_ipython\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrun_line_magic\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'matplotlib'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'inline'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0mtopo\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mloadtxt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'../../data/topo.asc'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelimiter\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m','\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/pyplot.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m   2280\u001b[0m     \u001b[0mdict\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__setitem__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"backend\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrcsetup\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_auto_backend_sentinel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2281\u001b[0m \u001b[0;31m# Set up the backend.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 2282\u001b[0;31m \u001b[0mswitch_backend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrcParams\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"backend\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m   2283\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   2284\u001b[0m \u001b[0;31m# Just to be safe.  Interactive mode can be turned on without\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/pyplot.py\u001b[0m in \u001b[0;36mswitch_backend\u001b[0;34m(newbackend)\u001b[0m\n\u001b[1;32m    219\u001b[0m         else \"matplotlib.backends.backend_{}\".format(newbackend.lower()))\n\u001b[1;32m    220\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 221\u001b[0;31m     \u001b[0mbackend_mod\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mimportlib\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mimport_module\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mbackend_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    222\u001b[0m     Backend = type(\n\u001b[1;32m    223\u001b[0m         \"Backend\", (matplotlib.backends._Backend,), vars(backend_mod))\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/importlib/__init__.py\u001b[0m in \u001b[0;36mimport_module\u001b[0;34m(name, package)\u001b[0m\n\u001b[1;32m    125\u001b[0m                 \u001b[0;32mbreak\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    126\u001b[0m             \u001b[0mlevel\u001b[0m \u001b[0;34m+=\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 127\u001b[0;31m     \u001b[0;32mreturn\u001b[0m \u001b[0m_bootstrap\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_gcd_import\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mlevel\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mpackage\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    128\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    129\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/ipykernel/pylab/backend_inline.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      8\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mmatplotlib\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m from matplotlib.backends.backend_agg import (\n\u001b[0m\u001b[1;32m     10\u001b[0m     \u001b[0mnew_figure_manager\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     11\u001b[0m     \u001b[0mFigureCanvasAgg\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/matplotlib/backends/backend_agg.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     49\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0m_has_pil\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 50\u001b[0;31m     \u001b[0;32mfrom\u001b[0m \u001b[0mPIL\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mImage\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     51\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     52\u001b[0m \u001b[0mbackend_version\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'v2.2'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/opt/anaconda3/lib/python3.7/site-packages/PIL/Image.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m     67\u001b[0m     \u001b[0;31m# Also note that Image.core is not a publicly documented interface,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     68\u001b[0m     \u001b[0;31m# and should be considered private and subject to change.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 69\u001b[0;31m     \u001b[0;32mfrom\u001b[0m \u001b[0;34m.\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0m_imaging\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mcore\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     70\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     71\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0m__version__\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"PILLOW_VERSION\"\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mImportError\u001b[0m: dlopen(/Users/beca4397/opt/anaconda3/lib/python3.7/site-packages/PIL/_imaging.cpython-37m-darwin.so, 2): Library not loaded: @rpath/libwebp.7.dylib\n  Referenced from: /Users/beca4397/opt/anaconda3/lib/libtiff.5.dylib\n  Reason: Incompatible library version: libtiff.5.dylib requires version 9.0.0 or later, but libwebp.7.dylib provides version 8.0.0"
     ]
    }
   ],
   "source": [
    "import numpy as np \n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "topo = np.loadtxt('../../data/topo.asc', delimiter=',')\n",
    "\n",
    "fig = plt.figure(figsize=(16.0, 3.0))\n",
    "\n",
    "axes1 = fig.add_subplot(1,3,1)\n",
    "axes2 = fig.add_subplot(1,3,2)\n",
    "axes3 = fig.add_subplot(1,3,3)\n",
    "\n",
    "axes1.plot(topo[:,0])\n",
    "axes1.set_ylim([2500,3900])\n",
    "axes1.set_ylabel('Elevation (m)')\n",
    "axes1.set_xlabel('<-- N   S --')\n",
    "axes1.set_title('West')\n",
    "\n",
    "axes2.plot(topo[:,int(len(topo)/2)])\n",
    "axes2.set_ylim([2500,3900])\n",
    "axes2.set_xlabel('<-- N   S --')\n",
    "axes2.set_title('Mid')\n",
    "\n",
    "axes3.plot(topo[:,-1])\n",
    "axes3.set_ylim([2500,3900])\n",
    "axes3.set_xlabel('<--N   S --')\n",
    "axes3.set_title('East')\n",
    "\n",
    "plt.show(fig) "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Practice your skills: Subplots of DEMs \n",
    " \n",
    "Make a 2x2 grid of subplots that use the function `imshow` to display\n",
    "each quarter of the dataset (ie. split down the middle in both x and y).\n",
    "\n",
    "* Don't label axes or add a colorbar. It can be tricky to do this with subplots.\n",
    "* To set the range of colors for one subplot, include the arguments `vmin` and `vmax`\n",
    "in `imshow` like this:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'plt' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-20-6fad2ef1c654>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mfig\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfigure\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfigsize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m16.0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3.0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0maxes1\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_subplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0maxes2\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_subplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0maxes3\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfig\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd_subplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mNameError\u001b[0m: name 'plt' is not defined"
     ]
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(16.0, 3.0))\n",
    "\n",
    "axes1 = fig.add_subplot(1,3,1)\n",
    "axes2 = fig.add_subplot(1,3,2)\n",
    "axes3 = fig.add_subplot(1,3,3)\n",
    "axes4 = fig.add_subplot(1,3,4)\n",
    "\n",
    "vmin = topo.min()\n",
    "vmax = topo.max()\n",
    "\n",
    "axes1.imshow(topo, vmin=vmin, vmax=vmax) \n",
    "axes1.set_ylim([2500,3900])\n",
    "axes1.set_ylabel('Elevation (m)')\n",
    "axes1.set_xlabel('<-- N   S --')\n",
    "axes1.set_title('West')\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
